package com.recharge.aop;


import com.recharge.common.annotation.RedisCachePut;
import com.recharge.common.util.RedisUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Component
@Aspect
public class RedisPutAspect {
    @Autowired
    private RedisUtil redisServer;


    @Pointcut("@annotation(com.recharge.common.annotation.RedisCachePut)")
    public void redisPutPointcut(){}



    @Around("redisPutPointcut()")
    public Object redisAdvice(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        RedisCachePut annotation = method.getAnnotation(RedisCachePut.class);

        String group = annotation.group();
        String key = annotation.key();
        boolean del = annotation.isDel();
        Object returnVale = null;
        String sPel="";
        if(!del){
            //继续执行目标方法
            try {
                returnVale = joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            Object[] args = joinPoint.getArgs();
            sPel = generateKeyBySpEL(key, method, joinPoint.getArgs());
            redisServer.set(group + sPel, returnVale, annotation.expire());
            return returnVale;
        }else {
            //继续执行目标方法
            try {
                returnVale = joinPoint.proceed();
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
            Object[] args = joinPoint.getArgs();
            sPel = generateKeyBySpEL(key, method, joinPoint.getArgs());
            redisServer.del(group + sPel);
        }

        return null;
    }


    /**
     * 用于SpEL表达式解析.
     */
    private SpelExpressionParser parser = new SpelExpressionParser();
    /**
     * 用于获取方法参数定义名字.
     */
    private DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();

    /**
     * 解析SpEl表达式返回值
     *
     * @param spELString, method, args
     * @return String
     */
    public String generateKeyBySpEL(String spELString, Method method, Object[] args) {
        String[] paramNames = nameDiscoverer.getParameterNames(method);
        Expression expression = parser.parseExpression(spELString);
        EvaluationContext context = new StandardEvaluationContext();
        for (int i = 0; i < args.length; i++) {
            context.setVariable(paramNames[i], args[i]);
        }
        return expression.getValue(context).toString();
    }
}
